<template>
  <div class="chat-container">
    <div class="chat-header">
      <h2>AI 助手</h2>
    </div>
    <div class="chat-messages" ref="messagesRef">
      <div v-for="message in chatHistory.messages" 
           :key="message.id"
           :class="['message-wrapper', message.role]">
        <div class="message">
          <div class="message-content" 
               v-if="message.role === 'user'">
            {{ message.content }}
          </div>
          <div v-else 
               class="message-content markdown-body"
               v-html="renderMarkdown(message)">
          </div>
          <div class="message-time">{{ formatTime(message.timestamp) }}</div>
        </div>
      </div>
    </div>
    
    <div class="chat-input">
      <div class="input-wrapper">
        <el-input
          v-model="userInput"
          type="textarea"
          :rows="3"
          :disabled="isTyping"
          placeholder="请输入您的问题...(Ctrl + Enter 发送)"
          @keyup.enter.ctrl="handleSend"
          class="custom-input"
        />
        <div 
          class="send-icon-wrapper"
          :class="{ disabled: isTyping || !userInput.trim() }"
          @click="handleSend"
        >
          <svg class="send-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
            <path d="M21.5 11.1001L3.5 2.10006C3.3 2.00006 3.1 2.00006 2.9 2.00006C2.7 2.00006 2.5 2.10006 2.3 2.20006C1.9 2.50006 1.9 3.00006 1.9 3.20006L3.2 9.80006C3.3 10.3001 3.7 10.7001 4.2 10.8001L11.2 12.4001C11.7 12.5001 11.7 13.2001 11.2 13.3001L4.2 14.9001C3.7 15.0001 3.3 15.4001 3.2 15.9001L1.9 22.5001C1.8 23.0001 2.2 23.5001 2.7 23.5001C2.9 23.5001 3 23.5001 3.2 23.4001L21.2 14.4001C21.6 14.2001 21.9 13.7001 21.9 13.2001V12.3001C21.9 11.8001 21.8 11.3001 21.5 11.1001Z" fill="currentColor"/>
          </svg>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, nextTick } from 'vue'
import { v4 as uuidv4 } from 'uuid'
import * as marked from 'marked'
import 'highlight.js/styles/github.css'
import 'github-markdown-css'
import hljs from 'highlight.js'
import type { ChatMessage, ChatHistory } from '../types/chat'

// 创建自定义渲染器用于 markdown 解析
const renderer = new marked.Renderer()

// 配置 markdown 解析器选项
marked.setOptions({
  renderer,
  highlight: function(code: string, lang: string) {
    // 代码高亮处理
    if (lang && hljs.getLanguage(lang)) {
      return hljs.highlight(code, { language: lang }).value
    }
    return hljs.highlightAuto(code).value
  },
  breaks: true, // 允许换行
  gfm: true,    // 启用 GitHub 风格 Markdown
  headerIds: false,
  mangle: false
})

// 扩展消息类型，添加时间戳
interface ExtendedChatMessage extends ChatMessage {
  timestamp: number
}

interface ExtendedChatHistory {
  messages: ExtendedChatMessage[]
}

// 响应式状态管理
const userInput = ref('') // 用户输入内容
const isTyping = ref(false) // 是否正在打字
const typingText = ref('') // 打字机效果的当前文本
const currentTypingMessage = ref<ExtendedChatMessage | null>(null) // 当前正在打字的消息
const messagesRef = ref<HTMLElement | null>(null) // 消息容器的引用

// 聊天历史记录
const chatHistory = reactive<ExtendedChatHistory>({
  messages: []
})

// 格式化时间戳为时:分格式
const formatTime = (timestamp: number) => {
  const date = new Date(timestamp)
  const hours = date.getHours().toString().padStart(2, '0')
  const minutes = date.getMinutes().toString().padStart(2, '0')
  return `${hours}:${minutes}`
}

// 渲染 markdown 内容
const renderMarkdown = (message: ExtendedChatMessage) => {
  try {
    // 如果是当前正在打字���消息，使用打字机文本，否则使用消息内容
    const content = message === currentTypingMessage.value ? typingText.value : message.content
    return marked.parse(content || '')
  } catch (error) {
    console.error('Markdown parsing error:', error)
    return '内容解析错误'
  }
}

// 添加打字机效果控制
const typewriterSpeed = 30 // 字符打印速度（毫秒）
const lineBreakDelay = 150 // 换行时的额外延迟（毫秒）

// 逐行打字机效果实现
const typewriterText = async (text: string, updateFn: (text: string) => void) => {
  let currentText = ''
  const lines = text.split('\n')
  
  for (let i = 0; i < lines.length; i++) {
    const line = lines[i]
    
    // 处理当前行的每个字符
    for (const char of line) {
      currentText += char
      updateFn(currentText)
      await new Promise(resolve => setTimeout(resolve, typewriterSpeed))
    }
    
    // 如果不是最后一行，添加换行符和额外延迟
    if (i < lines.length - 1) {
      currentText += '\n'
      updateFn(currentText)
      await new Promise(resolve => setTimeout(resolve, lineBreakDelay))
    }
  }
}

// 处理流式响应数据
const processStream = async (response: Response, message: ExtendedChatMessage) => {
  const reader = response.body?.getReader()
  if (!reader) return

  isTyping.value = true
  currentTypingMessage.value = message
  typingText.value = ''
  let fullText = ''
  const decoder = new TextDecoder()

  try {
    // 首先收集完整的响应文本
    while (true) {
      const { done, value } = await reader.read()
      if (done) break
      fullText += decoder.decode(value)
    }

    // 使用逐行打字机效果显示文本
    await typewriterText(fullText, (text) => {
      typingText.value = text
      scrollToBottom()
    })

    message.content = fullText
    await scrollToBottom()
  } catch (error) {
    console.error('Stream processing error:', error)
    message.content = '读取响应错误'
  } finally {
    isTyping.value = false
    currentTypingMessage.value = null
  }
}

// 滚动到消息底部
const scrollToBottom = async () => {
  await nextTick()
  if (messagesRef.value) {
    messagesRef.value.scrollTop = messagesRef.value.scrollHeight
  }
}

// 处理发送消息
const handleSend = async () => {
  if (isTyping.value || !userInput.value.trim()) return
  
  // 创建并添加用户消息
  const userMessage: ExtendedChatMessage = {
    role: 'user',
    content: userInput.value,
    id: uuidv4(),
    timestamp: Date.now()
  }
  chatHistory.messages.push(userMessage)
  userInput.value = ''
  await scrollToBottom()
  
  // 创建并添加助手消息（初始为空）
  const assistantMessage: ExtendedChatMessage = {
    role: 'assistant',
    content: '',
    id: uuidv4(),
    timestamp: Date.now()
  }
  chatHistory.messages.push(assistantMessage)
  
  try {
    // 发送请求到服务器
    const response = await fetch('http://localhost:3000/chat', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ message: userMessage.content }),
    })

    if (!response.ok) throw new Error('Network response was not ok')
    // 处理流式响应
    await processStream(response, assistantMessage)
  } catch (error) {
    console.error('Error:', error)
    assistantMessage.content = '抱歉，发生错误，请稍后重试。'
  }
}
</script>

<style>
@import 'github-markdown-css/github-markdown.css';

.chat-container {
  height: 100%;
  display: flex;
  flex-direction: column;
  padding: 0;
  box-sizing: border-box;
  overflow: hidden;
  background-color: #f0f2f5;
}

.chat-header {
  padding: 16px;
  background-color: #fff;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  z-index: 1;
}

.chat-header h2 {
  margin: 0;
  color: #333;
  font-size: 18px;
}

.chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: 20px 0;
  scroll-behavior: smooth;
}

.chat-messages::-webkit-scrollbar {
  width: 6px;
}

.chat-messages::-webkit-scrollbar-track {
  background: transparent;
}

.chat-messages::-webkit-scrollbar-thumb {
  background-color: rgba(0, 0, 0, 0.1);
  border-radius: 3px;
}

.message-wrapper {
  margin-bottom: 20px;
  display: flex;
  flex-direction: column;
  padding: 0 20px;
}

.message {
  position: relative;
  padding: 16px 20px;
  border-radius: 12px;
  max-width: 92%;
  min-width: 320px;
  box-shadow: 0 2px 6px rgba(0,0,0,0.1);
}

.user {
  align-items: flex-end;
}

.assistant {
  align-items: flex-start;
}

.user .message {
  background-color: #95ec69;
  margin-left: auto;
}

.assistant .message {
  background-color: #fff;
  margin-right: auto;
}

.message-time {
  font-size: 12px;
  color: #999;
  margin-top: 6px;
  padding: 0 4px;
  text-align: right;
}

.chat-input {
  padding: 20px 24px;
  background-color: #fff;
  box-shadow: 0 -2px 8px rgba(0,0,0,0.05);
  border-top: 1px solid #ebeef5;
}

.input-wrapper {
  position: relative;
  width: 100%;
}

.chat-input .custom-input {
  width: 100%;
}

.chat-input .custom-input :deep(.el-textarea__inner) {
  resize: none;
  height: 80px;
  border-radius: 16px;
  padding: 12px 50px 12px 16px;
  font-size: 15px;
  line-height: 1.6;
  border: 2px solid #ebeef5;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  box-shadow: 0 2px 6px rgba(0,0,0,0.02);
  background-color: #f8fafc;
  color: #2c3e50;
}

.chat-input .custom-input :deep(.el-textarea__inner:hover) {
  border-color: #dcdfe6;
  background-color: #fff;
}

.chat-input .custom-input :deep(.el-textarea__inner:focus) {
  border-color: #409eff;
  background-color: #fff;
  box-shadow: 0 0 0 3px rgba(64,158,255,0.1);
  outline: none;
}

.chat-input .custom-input :deep(.el-textarea__inner:disabled) {
  background-color: #f5f7fa;
  border-color: #e4e7ed;
  color: #909399;
  cursor: not-allowed;
}

/* 发送图标包装器样式 */
.send-icon-wrapper {
  position: absolute;
  right: 12px;
  bottom: 12px;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  border-radius: 50%;
  background-color: #409eff;
  transition: all 0.3s ease;
  color: white;
  transform: rotate(-45deg);
  padding: 0; /* 移除内边距 */
}

.send-icon-wrapper:hover:not(.disabled) {
  background-color: #66b1ff;
  transform: rotate(-45deg) scale(1.1);
}

/* 发送图标样式 */
.send-icon {
  width: 16px;
  height: 16px;
  transform: translate(-0.5px, -0.5px); /* 微调位置 */
  display: block; /* 确保图标作为块级元素 */
}

/* 禁用状态样式 */
.send-icon-wrapper.disabled {
  background-color: #a0cfff;
  cursor: not-allowed;
  opacity: 0.7;
}

/* 响应式调整 */
@media screen and (max-width: 768px) {
  .send-icon-wrapper {
    width: 28px;
    height: 28px;
    right: 10px;
    bottom: 10px;
  }

  .send-icon {
    width: 14px; /* 稍微调小一点 */
    height: 14px;
  }
}

/* 调整字数统计位置 */
.chat-input .custom-input :deep(.el-textarea__count) {
  right: 52px;
  bottom: 8px;
}

.markdown-body {
  font-size: 14px;
  background-color: transparent !important;
}

.markdown-body pre {
  margin: 1em -10px;
  padding: 16px 20px;
  background-color: #f6f8fa;
  border-radius: 8px;
  overflow-x: auto;
}

.markdown-body code {
  background-color: rgba(175,184,193,0.2);
  border-radius: 6px;
  padding: 0.2em 0.4em;
}

.markdown-body img.markdown-image {
  max-width: 100%;
  border-radius: 8px;
  margin: 8px 0;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  transition: transform 0.3s ease, opacity 0.3s ease;
  opacity: 1;
}

.markdown-body img.markdown-image.loading {
  opacity: 0.5;
  animation: image-loading 1.5s infinite;
}

.markdown-body img.markdown-image:not(.loading):hover {
  transform: scale(1.02);
}

.message-content {
  word-break: break-word;
  white-space: pre-wrap;
  line-height: 1.6;
  font-size: 15px;
  max-width: 100%;
}

.message-content.markdown-body {
  padding: 0;
}

.message-content.markdown-body > * {
  margin: 0.8em 0;
}

.message-content.markdown-body > *:first-child {
  margin-top: 0;
}

.message-content.markdown-body > *:last-child {
  margin-bottom: 0;
}

/* 确保代码块正确显示 */
.markdown-body pre code {
  padding: 0;
  background: transparent;
  font-size: 14px;
  line-height: 1.6;
  white-space: pre;
  word-break: normal;
}

/* 添加图片加载动画 */
@keyframes image-loading {
  0% { opacity: 0.5; }
  50% { opacity: 0.7; }
  100% { opacity: 0.5; }
}

.markdown-image.loading {
  animation: image-loading 1.5s infinite;
}

/* 优化 markdown 内容样式 */
.message-content {
  word-break: break-word;
  white-space: pre-wrap;
  line-height: 1.6;
  font-size: 15px;
}

.message-content.markdown-body {
  padding: 0;
}

.message-content.markdown-body > * {
  margin: 0.8em 0;
}

/* 优化代码块样式 */
.markdown-body pre code {
  white-space: pre-wrap;
  word-break: break-all;
  display: block;
  padding: 1.2em;
  background: #f6f8fa;
  border-radius: 8px;
  line-height: 1.5;
  font-size: 14px;
  margin: 1em 0;
}

/* 优化标题样式 */
.markdown-body h1 {
  font-size: 1.6em;
  border-bottom: none;
  padding-bottom: 0.2em;
}

.markdown-body h2 {
  font-size: 1.4em;
  border-bottom: none;
  padding-bottom: 0.2em;
}

/* 优化列表样式 */
.markdown-body ul, 
.markdown-body ol {
  padding-left: 1.5em;
}

/* 优化引用样式 */
.markdown-body blockquote {
  border-left: 4px solid #dfe2e5;
  color: #666;
  margin: 1em 0;
  padding: 0 1em;
}

/* 优化内联代码样式 */
.markdown-body code:not(pre code) {
  background-color: rgba(175,184,193,0.2);
  border-radius: 4px;
  padding: 0.2em 0.4em;
  font-size: 0.9em;
}

/* 优化聊天容器样式 */
.chat-container {
  height: 100%;
  display: flex;
  flex-direction: column;
  padding: 0;
  box-sizing: border-box;
  overflow: hidden;
  background-color: #f0f2f5;
}

/* 优化消息列表样式 */
.chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: 20px 0;
  scroll-behavior: smooth;
}

/* 优化输入区域样式 */
.chat-input {
  padding: 20px 24px;
  background-color: #fff;
  box-shadow: 0 -2px 8px rgba(0,0,0,0.05);
  border-top: 1px solid #ebeef5;
}

.input-wrapper {
  position: relative;
  width: 100%;
}

.chat-input .custom-input {
  width: 100%;
}

.chat-input .custom-input :deep(.el-textarea__inner) {
  resize: none;
  height: 80px;
  border-radius: 16px;
  padding: 12px 50px 12px 16px;
  font-size: 15px;
  line-height: 1.6;
  border: 2px solid #ebeef5;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  box-shadow: 0 2px 6px rgba(0,0,0,0.02);
  background-color: #f8fafc;
  color: #2c3e50;
}

.chat-input .custom-input :deep(.el-textarea__inner:hover) {
  border-color: #dcdfe6;
  background-color: #fff;
}

.chat-input .custom-input :deep(.el-textarea__inner:focus) {
  border-color: #409eff;
  background-color: #fff;
  box-shadow: 0 0 0 3px rgba(64,158,255,0.1);
  outline: none;
}

.chat-input .custom-input :deep(.el-textarea__inner:disabled) {
  background-color: #f5f7fa;
  border-color: #e4e7ed;
  color: #909399;
  cursor: not-allowed;
}

/* 发送图标包装器样式 */
.send-icon-wrapper {
  position: absolute;
  right: 12px;
  bottom: 12px;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  border-radius: 50%;
  background-color: #409eff;
  transition: all 0.3s ease;
  color: white;
  transform: rotate(-45deg);
  padding: 0; /* 移除内边距 */
}

.send-icon-wrapper:hover:not(.disabled) {
  background-color: #66b1ff;
  transform: rotate(-45deg) scale(1.1);
}

/* 发送图标样式 */
.send-icon {
  width: 16px;
  height: 16px;
  transform: translate(-0.5px, -0.5px); /* 微调位置 */
  display: block; /* 确保图标作为块级元素 */
}

/* 禁用状态样式 */
.send-icon-wrapper.disabled {
  background-color: #a0cfff;
  cursor: not-allowed;
  opacity: 0.7;
}

/* 响应式调整 */
@media screen and (max-width: 768px) {
  .send-icon-wrapper {
    width: 28px;
    height: 28px;
    right: 10px;
    bottom: 10px;
  }

  .send-icon {
    width: 14px; /* 稍微调小一点 */
    height: 14px;
  }
}

/* 调整字数统计位置 */
.chat-input .custom-input :deep(.el-textarea__count) {
  right: 52px;
  bottom: 8px;
}
</style> 